package com.buli.blmall.admin.core.filter;

import com.buli.blmall.admin.common.domain.SysLoginUser;
import com.buli.blmall.admin.consts.CacheKey;
import com.buli.blmall.admin.consts.Constants;
import com.buli.blmall.admin.consts.PathConstst;
import com.buli.blmall.admin.core.horder.LoginUserHolder;
import com.buli.blmall.admin.core.security.domain.AuthenticationUser;
import com.buli.blmall.admin.utils.JwtUtil;
import com.buli.blmall.admin.utils.PathMatchUtil;
import com.buli.blmall.admin.core.cache.RedisClient;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.Arrays;

/**
 *  - 位于安全处理的最前端
 *  - 按添加顺序依次执行（通过 `addFilterBefore` 控制）
 *  - 主要职责：请求预处理、身份认证、上下文设置
 * @author xiang.gao
 * @date 2025/3/4 18:38
 */
@Component
public class AuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private RedisClient redisClient;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String jwtToken = request.getHeader(Constants.AUTHORIZATION_KEY);
        if (StringUtils.isNotBlank(jwtToken)) {
            if (!JwtUtil.checkToken(jwtToken)) {
                throw new BadCredentialsException("token invalid");
            }
            Claims tokenBody = JwtUtil.getTokenBody(jwtToken);
            String token = (String) tokenBody.get("token");
            if (StringUtils.isBlank(token)) {
                throw new BadCredentialsException("token invalid");
            }
            SysLoginUser sysLoginUser = redisClient.getValue(CacheKey.SYSTEM_LOGIN_TOKEN.concat(token));
            if (sysLoginUser == null) {
                throw new BadCredentialsException("token invalid");
            }
            //设置认证信息
            AuthenticationUser authenticationUser = new AuthenticationUser(sysLoginUser);
            LoginUserHolder.set(sysLoginUser);
            SecurityContextHolder.getContext().setAuthentication(authenticationUser);
        }
        filterChain.doFilter(request, response);
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        return Arrays.stream(PathConstst.EXCLUDE_PATH).anyMatch(path -> PathMatchUtil.match(path, request.getServletPath()));
    }
}
